package com.mercadopago;

import java.io.File;
import java.io.InputStream;
import java.io.Reader;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;

import com.mercadopago.exceptions.MercadoPagoParseXmlException;
import com.mercadopago.types.Result;

public final class ParseXmlProcessStatus {
	
	private Log logger = LogFactory.getLog(getClass());

	private String xsd;

	private JAXBContext context;

	private Schema schema;

	private Unmarshaller unmarshaller;

	public ParseXmlProcessStatus() {
		logger.debug("inicializando ParseXmlProcessStatus");
		xsd = Result.class.getResource("./").getPath()
				.replace("/com/mercadopago/types/", "")
				.concat("/mercadopago-1.0.xsd");
	}

	private void createContext() throws MercadoPagoParseXmlException {
		if(context != null)
			return;
		
		try {
			logger.debug("criando context para Result.class");
			context = JAXBContext.newInstance(Result.class);
		} catch (JAXBException e) {
			throw new MercadoPagoParseXmlException(e);
		}
	}

	private void schemaFactory() throws MercadoPagoParseXmlException {
		createContext();
		
		if(schema != null)
			return;
		
		try {
			logger.debug("criando schema");
			SchemaFactory schemaFactory = SchemaFactory
					.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
			schema = schemaFactory.newSchema(new File(xsd));
		} catch (SAXException e) {
			throw new MercadoPagoParseXmlException(e);
		}
	}

	private void createUnmarshaller() throws MercadoPagoParseXmlException {
		schemaFactory();
		
		if(unmarshaller != null)
			return;
		
		try {
			logger.debug("criando unmarshaller");
			unmarshaller= context.createUnmarshaller();
			unmarshaller.setSchema(schema);
		} catch (JAXBException e) {
			throw new MercadoPagoParseXmlException(e);
		}
	}
	
	public final Result parseResult(File file) throws MercadoPagoParseXmlException {
		createUnmarshaller();
		
		try {
			logger.debug("fazendo parse");
			return (Result) unmarshaller.unmarshal(file);
		} catch (Exception e) {
			throw new MercadoPagoParseXmlException(e);
		}
	}
	
	public final Result parseResult(InputStream stream) throws MercadoPagoParseXmlException {
		createUnmarshaller();
		
		try {
			logger.debug("fazendo parse");
			return (Result) unmarshaller.unmarshal(stream);
		} catch (Exception e) {
			throw new MercadoPagoParseXmlException(e);
		}
	}
	
	public final Result parseResult(Reader reader) throws MercadoPagoParseXmlException {
		createUnmarshaller();
		
		try {
			logger.debug("fazendo parse");
			return (Result) unmarshaller.unmarshal(reader);
		} catch (Exception e) {
			throw new MercadoPagoParseXmlException(e);
		}
	}
	
}
